Passing custom class object to web workers
· 4 minutes of read · viewsAnnoy level | Time wasted[1] | Solvable |
---|---|---|
6h | Kinda |
Web workers are powerful sorcery in the battle against performance demons. When utilizing them, everyone gains a +10🛡️ defense bonus against senior devs and a +5🐎 boost to development stamina.
However, like every sword, they have two edges. One of these edges, hidden in the depths of MDN, can become a real pain in the ass when attempting to pass something more complex than an ordinary Object[2].
Let's take a look at the simple planWorker.ts code:
onmessage = function (e: MessageEvent): void {
const x = e.data.x as number;
const y = e.data.y as number;
const layer = new Layer(x, y); // layer type is Layer
postMessage({ layer: layer });
};
The worker gathers the data and then creates a new Layer
with the given arguments. After the work is done, the new layer is sent back and can be accessed as e.data.layer
.
Now, let's examine the process
method of the Frame
class that created this web worker in attempt to push the returned object named layer
into the layers
property in its class:
export default class Frame {
layers: Layer[] = [];
public process({ x, y }: Coords): void {
const worker = new Worker(
new URL("../utils/planWorker.ts", import.meta.url)
);
worker.onmessage = (e: MessageEvent) => {
const layer: Layer = e.data.layer; // layer type is Layer, right?
this.layers.push(layer);
worker.terminate();
};
worker.postMessage({
x: x,
y: y,
});
}
}
How pleasantly surprising it was to discover that suddenly methods working on the layers
array couldn't access some of the methods from the Layer
class. Well I think that means it's...
After many hours of debugging, I discovered this GitHub question and realized that, unlike every other time, the fault was not on my side.
The issue lay within the web worker messaging system.
Caution
If your custom class contains something more then just properties then buckle your seatbelt Dorothy, 'cause they are going bye-bye![3]. The structured cloning algorithm used by web worker message system will ignore all of yours:
- property descriptors
- decorators
- setters,
- getters,
- methods
The solution to handle this ✨feature✨ is to either construct new object properties to maintain the current state of the original class or utilize JSON. However, the loss of methods may be unacceptable for some, thus making web workers less than ideal for handling more complex custom class objects[4].
I learn something for sure, but you know... I could spend that time more productive, like watching Adventure Time instead. ↩︎
Web workers can also pass
Array
,ArrayBuffer
,Boolean
,DataView
,Date
,Map
,Number
, Primitive types, except symbol,RegExp
,Set
,String
andTypedArray
. ↩︎Reference to Matrix movie. ↩︎
Other constrain may be the fact that all objects are copied not shared when used by messages system. Sharing data is possible, but not with the objects. ↩︎